package com.example.callcenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.callcenter.dto.CallTaskDTO;
import com.example.callcenter.dto.TaskMessageDTO;
import com.example.callcenter.entity.*;
import com.example.callcenter.mapper.CallTaskMapper;
import com.example.callcenter.mapper.CustomerMapper;
import com.example.callcenter.mapper.SysUserMapper;
import com.example.callcenter.rabbitmq.TaskDistributeProducer;
import com.example.callcenter.service.ICallRecordService;
import com.example.callcenter.service.ICallTaskService;
import com.example.callcenter.util.ResultUtil;
import com.example.callcenter.util.UserContext;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Service
public class CallTaskServiceImpl extends ServiceImpl<CallTaskMapper, CallTask> implements ICallTaskService {

    private static final Logger logger = LoggerFactory.getLogger(CallTaskServiceImpl.class);

    // 任务状态常量
    public static final int TASK_STATUS_NOT_STARTED = 0; // 未开始
    public static final int TASK_STATUS_RUNNING = 1;    // 进行中
    public static final int TASK_STATUS_PAUSED = 3;     // 已暂停
    public static final int TASK_STATUS_COMPLETED = 2;  // 已完成

    // 客户状态常量
    public static final int CUSTOMER_STATUS_NOT_CALLED = 0; // 未外呼
    public static final int CUSTOMER_STATUS_CALLED = 1;    // 已外呼

    @Autowired
    private CallTaskMapper taskMapper;

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private ICallRecordService recordService;

    @Autowired
    private TaskDistributeProducer taskProducer;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;

    // 配置化延迟时间（默认5秒）
    @Value("${call.delay.seconds:5}")
    private int callDelaySeconds;

    // 存储正在运行的任务（任务ID → 调度任务句柄）
    private final Map<Long, ScheduledFuture<?>> runningTasks = new ConcurrentHashMap<>();

    // 存储坐席状态（坐席ID → 是否忙碌）
    private final Map<Long, Boolean> salesStatus = new ConcurrentHashMap<>();

    @Override
    @Transactional
    public ResultUtil createTask(CallTaskDTO taskDTO) {
        CallTask task = new CallTask();
        task.setTaskName(taskDTO.getTaskName());
        task.setTotalCount(taskDTO.getTotalCount());
        task.setCreateUserId(UserContext.getUserId());
        task.setStatus(TASK_STATUS_NOT_STARTED);
        task.setCreateTime(LocalDateTime.now());
        // 初始化统计字段为0（避免后续null）
        task.setCalledCount(0);
        task.setSuccessCount(0);
        task.setFailCount(0);
        taskMapper.insert(task);
        return ResultUtil.success("任务创建成功，任务ID：" + task.getId());
    }

    @Override
    @Transactional
    public ResultUtil startTask(Long taskId) {
        RLock lock = redissonClient.getLock("task:start:" + taskId);
        try {
            if (!lock.tryLock(5, 30, TimeUnit.SECONDS)) {
                return ResultUtil.error("任务启动中，请稍后再试");
            }

            CallTask task = taskMapper.selectById(taskId);
            if (task == null) {
                return ResultUtil.error("任务不存在");
            }

            if (task.getStatus() == TASK_STATUS_RUNNING) {
                return ResultUtil.error("任务正在进行中");
            }
            if (task.getStatus() == TASK_STATUS_COMPLETED) {
                return ResultUtil.error("任务已完成，无法启动");
            }

            task.setStatus(TASK_STATUS_RUNNING);
            if (task.getStartTime() == null) {
                task.setStartTime(LocalDateTime.now());
            }
            taskMapper.updateById(task);

            // 启动初始外呼（只触发一次，后续由外呼结果触发）
            startInitialCalling(taskId);
            return ResultUtil.success("任务已启动，开始自动外呼");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return ResultUtil.error("任务启动被中断");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional
    public ResultUtil pauseTask(Long taskId) {
        RLock lock = redissonClient.getLock("task:pause:" + taskId);
        try {
            if (!lock.tryLock(5, 30, TimeUnit.SECONDS)) {
                return ResultUtil.error("任务处理中，请稍后再试");
            }

            CallTask task = taskMapper.selectById(taskId);
            if (task == null) {
                return ResultUtil.error("任务不存在");
            }

            if (task.getStatus() != TASK_STATUS_RUNNING) {
                return ResultUtil.error("任务当前状态不支持暂停操作，当前状态：" + task.getStatus());
            }

            task.setStatus(TASK_STATUS_PAUSED);
            task.setPauseTime(LocalDateTime.now());
            taskMapper.updateById(task);

            // 停止所有调度任务
            stopAutoCalling(taskId);
            return ResultUtil.success("任务已暂停");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return ResultUtil.error("任务暂停被中断");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public IPage<CallTask> getTaskPage(Integer pageNum, Integer pageSize, String keyword) {
        IPage<CallTask> page = new Page<>(pageNum, pageSize);
        QueryWrapper<CallTask> query = new QueryWrapper<>();
        if (keyword != null) {
            query.like("task_name", keyword);
        }
        query.orderByDesc("create_time");
        return taskMapper.selectPage(page, query);
    }

    @Override
    public void processCallResult(TaskMessageDTO resultDTO) {
        RLock taskLock = redissonClient.getLock("task:update:" + resultDTO.getTaskId());
        try {
            if (taskLock.tryLock(3, 10, TimeUnit.SECONDS)) {
                doProcessCallResult(resultDTO);

                // 标记坐席为空闲
                salesStatus.put(resultDTO.getSalesId(), false);

                // 调度下一通电话（延迟配置的秒数）
                scheduleNextCall(resultDTO.getTaskId());
                logger.info("任务 {} 下一通电话将在 {} 秒后触发", resultDTO.getTaskId(), callDelaySeconds);
            } else {
                logger.warn("获取任务 {} 锁失败，稍后重试", resultDTO.getTaskId());
                // 锁获取失败时，延迟后重试调度
                scheduleNextCall(resultDTO.getTaskId());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            logger.error("处理任务 {} 中断", resultDTO.getTaskId(), e);
            // 中断时仍尝试调度下一个客户
            scheduleNextCall(resultDTO.getTaskId());
        } catch (Exception e) {
            logger.error("处理任务 {} 异常", resultDTO.getTaskId(), e);
            // 任何异常都尝试调度下一个客户
            scheduleNextCall(resultDTO.getTaskId());
        } finally {
            if (taskLock.isHeldByCurrentThread()) {
                taskLock.unlock();
            }
        }
    }

    @Transactional
    protected void doProcessCallResult(TaskMessageDTO resultDTO) {
        // 1. 保存通话记录
        CallRecord record = new CallRecord();
        record.setTaskId(resultDTO.getTaskId());
        record.setCustomerId(resultDTO.getCustomerId());
        record.setSalesId(resultDTO.getSalesId());
        record.setDuration(resultDTO.getDuration());
        record.setResult(resultDTO.getResult() == null ? "默认结果" : resultDTO.getResult());
        record.setRemark(resultDTO.getRemark());
        record.setCallTime(LocalDateTime.now());
        record.setCreateTime(LocalDateTime.now());
        recordService.save(record);

        // 2. 更新客户状态
        Customer customer = customerMapper.selectById(resultDTO.getCustomerId());
        if (customer != null) { // 避免客户不存在导致的空指针
            customer.setStatus(CUSTOMER_STATUS_CALLED);
            customer.setCallTime(LocalDateTime.now());
            customerMapper.updateById(customer);
        } else {
            logger.warn("客户 {} 不存在，跳过状态更新", resultDTO.getCustomerId());
        }

        // 3. 更新任务统计（核心修复：处理null问题）
        CallTask task = taskMapper.selectById(resultDTO.getTaskId());
        if (task != null) {
            // 安全更新calledCount（避免null）
            int currentCalled = task.getCalledCount() == null ? 0 : task.getCalledCount();
            task.setCalledCount(currentCalled + 1);

            // 安全更新successCount（避免null）
            if ("SUCCESS".equals(resultDTO.getResult())) {
                int currentSuccess = task.getSuccessCount() == null ? 0 : task.getSuccessCount();
                task.setSuccessCount(currentSuccess + 1);
            }

            // 4. 检查是否所有客户已外呼
            long unCalled = customerMapper.selectCount(new QueryWrapper<Customer>()
                    .eq("task_id", resultDTO.getTaskId())
                    .eq("status", CUSTOMER_STATUS_NOT_CALLED));

            if (unCalled == 0) {
                task.setStatus(TASK_STATUS_COMPLETED);
                task.setEndTime(LocalDateTime.now());
            }
            taskMapper.updateById(task);
        } else {
            logger.warn("任务 {} 不存在，跳过统计更新", resultDTO.getTaskId());
        }
    }

    @Async("businessExecutor")
    protected void startInitialCalling(Long taskId) {
        RLock lock = redissonClient.getLock("task:start-initial:" + taskId);
        try {
            if (!lock.tryLock(5, 30, TimeUnit.SECONDS)) {
                logger.warn("任务 {} 初始外呼已在进行中", taskId);
                return;
            }

            CallTask task = taskMapper.selectById(taskId);
            if (task == null || task.getStatus() != TASK_STATUS_RUNNING) {
                return;
            }

            // 触发第一次外呼
            scheduleNextCall(taskId);
            logger.info("已启动任务 {} 的初始外呼", taskId);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            logger.error("启动任务 {} 初始外呼被中断", taskId, e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    protected void scheduleNextCall(Long taskId) {
        // 计算延迟后的执行时间（带时区信息）
        Instant executeTime = LocalDateTime.now()
                .plusSeconds(callDelaySeconds)
                .atZone(ZoneId.systemDefault())
                .toInstant();

        logger.info("任务 {} 下一通电话已调度，将在 {} 秒后执行（预计时间：{}）",
                taskId,
                callDelaySeconds,
                executeTime);

        // 使用 Instant 作为调度时间参数
        ScheduledFuture<?> future = taskScheduler.schedule(() -> {
            try {
                // 检查任务状态
                CallTask task = taskMapper.selectById(taskId);
                if (task == null || task.getStatus() != TASK_STATUS_RUNNING) {
                    logger.info("任务 {} 已停止或不存在，取消调度", taskId);
                    runningTasks.remove(taskId); // 清理无效任务
                    return;
                }

                // 获取下一个待外呼客户
                Customer customer = getNextUncalledCustomer(taskId);
                if (customer == null) {
                    // 所有客户已外呼完成，标记任务结束
                    task.setStatus(TASK_STATUS_COMPLETED);
                    task.setEndTime(LocalDateTime.now());
                    taskMapper.updateById(task);
                    runningTasks.remove(taskId);
                    logger.info("任务 {} 已完成，所有客户已外呼", taskId);
                    return;
                }

                // 获取可用坐席（优先空闲坐席）
                SysUser availableSales = getAvailableSales();
                if (availableSales == null) {
                    logger.warn("无可用坐席，任务 {} 将在 {} 秒后重试", taskId, callDelaySeconds);
                    // 递归调用：延迟后再次尝试调度
                    scheduleNextCall(taskId);
                    return;
                }

                // 标记坐席为忙碌状态
                salesStatus.put(availableSales.getId(), true);

                // 构建外呼消息并发送
                TaskMessageDTO message = new TaskMessageDTO();
                message.setTaskId(taskId);
                message.setCustomerId(customer.getId());
                message.setCustomerName(customer.getName());
                message.setPhone(customer.getPhone());
                message.setSalesId(availableSales.getId());

                taskProducer.distributeTask(message);
                logger.info("已分配客户 {} 给坐席 {}，任务ID：{}",
                        customer.getId(),
                        availableSales.getId(),
                        taskId);

            } catch (Exception e) {
                logger.error("任务 {} 调度异常：{}", taskId, e.getMessage(), e);
                // 异常后仍尝试调度下一个客户
                scheduleNextCall(taskId);
            }
        }, executeTime);

        // 记录任务调度，用于后续取消
        runningTasks.put(taskId, future);
    }

    protected void stopAutoCalling(Long taskId) {
        ScheduledFuture<?> future = runningTasks.remove(taskId);
        if (future != null) {
            future.cancel(true);
            logger.info("已停止任务 {} 的自动外呼调度", taskId);
        }

        // 重置所有坐席状态为空闲
        salesStatus.replaceAll((k, v) -> false);
    }

    private Customer getNextUncalledCustomer(Long taskId) {
        QueryWrapper<Customer> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("task_id", taskId)
                .eq("status", CUSTOMER_STATUS_NOT_CALLED)
                .orderByAsc("id")
                .last("LIMIT 1");
        return customerMapper.selectOne(queryWrapper);
    }

    private SysUser getAvailableSales() {
        // 查询所有销售坐席
        List<SysUser> salesList = userMapper.selectList(new QueryWrapper<SysUser>()
                .eq("role", "SALES"));

        // 优先返回空闲坐席
        for (SysUser sales : salesList) {
            // 未标记状态的坐席默认视为空闲
            if (!salesStatus.getOrDefault(sales.getId(), false)) {
                return sales;
            }
        }

        // 若所有坐席都忙碌，返回null（等待下次调度）
        return null;
    }
}